// package: rewords-server-2024
// filename: common
// author: diogoxiang@gmail.com
// time: 2024/11/22 14:10

package common

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/gogf/gf/v2/util/grand"
	"go.mongodb.org/mongo-driver/bson"
	"rewords-server-2024/internal/model/input/form"
	"rewords-server-2024/internal/model/outin"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gfile"

	"github.com/qiniu/go-sdk/v7/auth/qbox"
	"github.com/qiniu/go-sdk/v7/storage"

	"rewords-server-2024/api/common"
	"rewords-server-2024/internal/consts"
	"rewords-server-2024/internal/library/cfg"
	"rewords-server-2024/internal/library/contexts"
	"rewords-server-2024/internal/model/entity"
	"rewords-server-2024/internal/service"
	"rewords-server-2024/utility/ztime"
)

var Upload = new(cUploadCtrl)

type cUploadCtrl struct{}

// GetQiniuToken 前端直传七牛
func (c *cUploadCtrl) GetQiniuToken(ctx context.Context, req *common.UploadQiniuReq) (res *common.UploadQiniuRes, err error) {
	accessKey := cfg.GConfig.Qiniu.AccessKey
	secretKey := cfg.GConfig.Qiniu.SecretKey
	bucket := cfg.GConfig.Qiniu.Bucket
	//cdnHost := config.GConfig.Qiniu.CdnHost

	putPolicy := storage.PutPolicy{
		Scope: bucket,
	}
	// token 有效
	putPolicy.Expires = 7200 //示例2小时有效期
	//putPolicy := storage.PutPolicy{
	//	Scope: bucket,
	//	ReturnBody: `{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}`,
	//}
	// 生成定制的返回值
	returnBody := fmt.Sprintf(`{"url":"%s/$(key)"}`, cfg.GConfig.Qiniu.CdnHost)
	putPolicy.ReturnBody = returnBody

	mac := qbox.NewMac(accessKey, secretKey)
	upToken := putPolicy.UploadToken(mac)

	res = &common.UploadQiniuRes{
		UploadToken: upToken,
	}

	return
}

func (c *cUploadCtrl) UploadFile(ctx context.Context, req *common.UploadFileReq) (res *common.UploadFileRes, err error) {
	r := g.RequestFromCtx(ctx)
	fileTemp, MaxSize, fileHost := newFunction()
	files := r.GetUploadFiles("file")

	if len(files) == 0 {
		return nil, gerror.New("未上传任何文件")
	}

	var fileInfos []common.FileInfo
	var uploadRecords []entity.SysUpload

	// 获取当前用户ID
	uid := contexts.GetUserId(ctx)

	for _, file := range files {
		if file.Size > MaxSize {
			return nil, gerror.Newf("文件 %s 超过最大限制 %dMB", file.Filename, cfg.GConfig.Setting.MaxTempsize)
		}

		// 生成唯一文件名
		ext := gfile.Ext(file.Filename)
		//uniqueName := grand.S(16) + ext
		// 使用正斜杠构建服务器路径
		//savePath := strings.ReplaceAll(gfile.Join(fileTemp, uniqueName), "\\", "/")
		// 构建公开访问URL
		//publicUrl := fileHost + "/temp/" + uniqueName
		var fileName string
		// 保存文件
		if fileName, err = file.Save(fileTemp, true); err != nil {
			return nil, gerror.Wrapf(err, "保存文件 %s 失败", file.Filename)
		}

		publicUrl := fileHost + "/temp/" + fileName
		// 收集文件信息
		fileInfos = append(fileInfos, common.FileInfo{
			OriginalName: file.Filename,
			SaveName:     fileName,
			SavePath:     publicUrl, // 使用公开访问URL而不是服务器路径
			Size:         file.Size,
			Type:         ext,
		})

		now := ztime.GetLocalTime()
		// 准备数据库记录
		uploadRecord := entity.SysUpload{
			Id:           grand.Letters(10), // 随机的ID
			OriginalName: file.Filename,
			SaveName:     fileName,
			SavePath:     publicUrl, // 使用公开访问URL而不是服务器路径
			Size:         file.Size,
			Type:         ext,
			Uid:          uid,
			CreatedAt:    &now,
			UpdatedAt:    &now,
		}
		uploadRecords = append(uploadRecords, uploadRecord)

	}

	// 批量插入数据库
	if err = service.Mgx().InsertMany(ctx, consts.CUpload, uploadRecords); err != nil {
		return nil, gerror.Wrap(err, "插入数据库失败")
	}

	return &common.UploadFileRes{
		Url:   fileInfos[0].SavePath,
		Id:    uploadRecords[0].Id,
		Files: fileInfos,
	}, nil
}

func (c *cUploadCtrl) UpInfo(ctx context.Context, req *common.UpInfoReq) (res *common.UploadFileRes, err error) {
	updataDoc := form.NewBuilder().
		Set("id", grand.Letters(10)).
		Set("original_name", req.Title).
		Set("save_path", req.Url).
		Set("created_at", ztime.GetLocalTime()).
		Build()

	err = service.Mgx().InsertOne(ctx, consts.CUpload, updataDoc)

	return
}

func (c *cUploadCtrl) Images(ctx context.Context, req *common.ImagesReq) (res *common.ImagesRes, err error) {

	result, err := service.Mgx().Find(ctx, consts.CUpload, bson.M{}, bson.M{}, req.PageNum, req.PageSize, nil)

	if err != nil {
		return nil, gerror.Wrap(err, "查询失败")
	}
	var list []outin.ImageItem

	if err = gconv.Struct(result, &list); err != nil {
		return nil, gerror.Wrap(err, "数据转换失败")
	}

	res = &common.ImagesRes{
		List: list,
	}

	return
}

func newFunction() (string, int64, string) {
	fileTemp := cfg.GConfig.Setting.UploadTmpDir
	MaxSize := cfg.GConfig.Setting.MaxTempsize * 1000000
	fileHost := cfg.GConfig.Setting.UploadDomain
	return fileTemp, MaxSize, fileHost
}
